package com.easylinkin.linkappapi.meterbilling.util;

import com.alibaba.fastjson.JSONObject;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.deviceattributestatus.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import com.easylinkin.linkappapi.deviceparm.entity.DeviceParm;
import com.easylinkin.linkappapi.deviceservice.entity.DeviceServices;
import com.easylinkin.linkappapi.deviceservice.service.DeviceServiceService;
import com.easylinkin.linkappapi.meterbilling.entity.MeterDeviceConfig;
import com.easylinkin.linkappapi.meterbilling.entity.RoomInfo;
import com.easylinkin.linkappapi.meterbilling.mapper.MeterDeviceConfigMapper;
import com.easylinkin.linkappapi.meterbilling.mapper.RoomInfoMapper;
import com.easylinkin.linkappapi.openapi.dto.ApiDownResultDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: linkapp-group-mydev
 * @description: 设备服务控制
 * @author: chenkaixuan
 * @create: 2021-08-06 18:01
 */
@Slf4j
@Component
public class MeterServiceControl {
    private static String SWITCH_CONTROL="switch_control";
    @Value("${linkapp.configDeviceExecuteConditionCommand:}")
    BigDecimal configDeviceExecuteConditionCommand;
    @Resource
    RoomInfoMapper roomInfoMapper;
    @Resource
    DeviceServiceService deviceServiceService;
    @Resource
    MeterDeviceConfigMapper meterDeviceConfigMapper;
    @Resource
    DeviceService deviceService;
    @Resource
    DeviceAttributeStatusService deviceAttributeStatusService;


    /***
     * 执行下发命令
     * @param roomInfo
     */
    public void executeDeviceCommand(RoomInfo roomInfo){
        if(configDeviceExecuteConditionCommand == null || roomInfo == null || roomInfo.getId() == null){
            return;
        }
        roomInfo = roomInfoMapper.selectById(roomInfo.getId());
        if(roomInfo == null || roomInfo.getId() == null){
            return;
        }
        MeterDeviceConfig meterDeviceConfig=new MeterDeviceConfig();
        meterDeviceConfig.setTenantId(roomInfo.getTenantId());
        meterDeviceConfig.setRoomId(roomInfo.getId());
        String switchState="switch_state";
        //电费余额
        BigDecimal electricityBalance = roomInfo.getElectricityBalance();
        //  < -1; = 0; > 1
        if(configDeviceExecuteConditionCommand.compareTo(electricityBalance) != -1){
            //设定值大于等于，关闸 余额 0：水表:1：电表
            meterDeviceConfig.setMeterType(1);
            configCommand(false,switchState,meterDeviceConfig);
        }else if(BigDecimal.ZERO.compareTo(electricityBalance) == -1){
            //设定值小于等于余额
            meterDeviceConfig.setMeterType(1);
            configCommand(true,switchState,meterDeviceConfig);
        }
        String valveState="valve_state";
        //水费余额
        BigDecimal waterBalance = roomInfo.getWaterBalance();
        if(configDeviceExecuteConditionCommand.compareTo(waterBalance) != -1){
            //设定值大于余额
            meterDeviceConfig.setMeterType(0);
            configCommand(false,valveState,meterDeviceConfig);
        }else if(BigDecimal.ZERO.compareTo(waterBalance) == -1){
            //设定值小于等于余额
            meterDeviceConfig.setMeterType(0);
            configCommand(true,valveState,meterDeviceConfig);
        }
    }

    /***
     * 配置下发参数
     * @param switchState switchState 1（true）开，0 关(false)     meterType 0：水表:1：电表
     * @param command
     */
    private void configCommand(boolean switchState,String command,MeterDeviceConfig meterDeviceConfig){
        List<MeterDeviceConfig> meterDeviceConfigList = meterDeviceConfigMapper.getMeterDeviceConfigList(meterDeviceConfig);
        if(meterDeviceConfigList == null || meterDeviceConfigList.size()<=0){
            return;
        }
        MeterDeviceConfig device = meterDeviceConfigList.get(0);
        String deviceCode = device.getDeviceCode();
        if(StringUtils.isEmpty(deviceCode)){
            return;
        }
        //查询当前实时设备属性
        List<DeviceAttributeStatus> latestDeviceAttributeStatusList = deviceAttributeStatusService.getLatestDeviceAttributeStatusList(deviceCode,null);
        if(latestDeviceAttributeStatusList == null || latestDeviceAttributeStatusList.size()<=0){
            return;
        }
        String propValue=null;
        for (DeviceAttributeStatus deviceAttributeStatus : latestDeviceAttributeStatusList) {
            if(!command.equals(deviceAttributeStatus.getPropCode())){
                continue;
            }
            propValue=deviceAttributeStatus.getPropValue();
            break;
        }
        //对应下发属性不存在，则退出
        if(StringUtils.isEmpty(propValue)){
            return;
        }
        Device queryDevice = new Device();
        queryDevice.setCode(deviceCode);
        List<Device> deviceList = deviceService.selectDevices(queryDevice);
        if(deviceList == null || deviceList.size()<=0){
            return;
        }
        Device oneByDeviceCode = deviceList.get(0);
        //不同的设备类型(0：水表:1：电表) 转换为不同的下发指令
        String original=getOriginal(switchState,meterDeviceConfig,oneByDeviceCode,command);
        //状态和现有一致
        if(propValue.equals(original)){
            return;
        }
        //获取当前设备在线状态，不一致则下发指令
        Integer delete=1;
        //状态和现有一致或者在linkthing不存在，不处理
        if(!delete.equals(oneByDeviceCode.getLinkthingDelete())){
            return;
        }
        HashMap<String,Object> commandMap=new HashMap<>();
        commandMap.put(command,original);
        executeCommand(deviceCode,commandMap);
    }

    /***
     * 执行下发命令
     * @param deviceCode
     * @param command
     */
    private void executeCommand(String deviceCode,HashMap<String,Object> command){
        Map<String, Object> downParameter=new HashMap<>();
        downParameter.put("device_id",deviceCode);
        downParameter.put("parameter",command);
        downParameter.put("service_id","switch_control");
        ApiDownResultDTO resultDTO = deviceServiceService.send(downParameter);
        if(resultDTO != null && !"0".equals(resultDTO.getCode())){
            log.error("水电表管理余额设定变动触发:"+JSONObject.toJSONString(resultDTO));
        }
    }

    /***
     * 根据不同的设备类型获取指令
     * @param switchState
     * @param meterDeviceConfig
     * @return
     */
    private String getOriginal(boolean switchState,MeterDeviceConfig meterDeviceConfig,Device oneByDeviceCode,String command){
        DeviceServices deviceServices = new DeviceServices();
        deviceServices.setDeviceUnitId(oneByDeviceCode.getDeviceUnitId());
        deviceServices.setIdentifier(SWITCH_CONTROL);
        List<DeviceServices> deviceServicesList = deviceServiceService.getDeviceServicesList(deviceServices);
        if(deviceServicesList == null || deviceServicesList.size()<=0){
            log.info("水电表管理余额设定变动触发-查询无下行服务:"+JSONObject.toJSONString(deviceServices));
            return null;
        }
        DeviceServices services = deviceServicesList.get(0);
        List<DeviceParm> paramList = services.getParamList();
        if(paramList == null || paramList.size()<=0){
            log.info("水电表管理余额设定变动触发-查询无下行服务:"+JSONObject.toJSONString(deviceServices));
            return null;
        }
        //获取name
        String name=null;
        //0：水表:1：电表
        if(meterDeviceConfig.getMeterType() == 1){
            name = ElectricMeterState.getName(switchState);
        }else{
            name = WaterMeterState.getName(switchState);
        }
        if(StringUtils.isEmpty(name)){
            log.info("水电表管理余额设定变动触发-查询枚举为空:switchState:{},MeterType:{}",switchState,meterDeviceConfig.getMeterType());
            return null;
        }
        for (DeviceParm m : paramList) {
            if(!command.equals(m.getIdentifier())){
                continue;
            }
            String specs = m.getSpecs();
            if(StringUtils.isEmpty(specs)){
                continue;
            }
            JSONObject jsonObject = JSONObject.parseObject(specs);
            if(jsonObject == null ||jsonObject.size()<=0){
                continue;
            }
            for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                if(entry.getValue() == null){
                    continue;
                }
                String value=(String)entry.getValue();
                if(value.indexOf(name) != -1){
                    return entry.getKey();
                }
            }
        }
        return null;
    }

    /***
     * 水表
     */
    private enum WaterMeterState{
        on(true,"0","开"),
        off(false,"1","关");
        WaterMeterState(boolean state, String original, String name) {
            this.state = state;
            this.original = original;
            this.name = name;
        }
        private boolean state;
        private String original;
        private String name;
        public static String getOriginal(boolean state){
            for (WaterMeterState waterMeterState : WaterMeterState.values()) {
                if(waterMeterState.state == state){
                    return  waterMeterState.original;
                }
            }
            return null;
        }
        public static String getName(boolean state){
            for (WaterMeterState waterMeterState : WaterMeterState.values()) {
                if(waterMeterState.state == state){
                    return  waterMeterState.name;
                }
            }
            return null;
        }
    }

    /***
     * 电表
     */
    private enum ElectricMeterState{
        on(true,"on","通"),
        off(false,"off","断");
        ElectricMeterState(boolean state, String original, String name) {
            this.state = state;
            this.original = original;
            this.name = name;
        }
        private boolean state;
        private String original;
        private String name;
        public static String getOriginal(boolean state){
            for (ElectricMeterState electricMeterState : ElectricMeterState.values()) {
                if(electricMeterState.state == state){
                    return  electricMeterState.original;
                }
            }
            return null;
        }
        public static String getName(boolean state){
            for (ElectricMeterState electricMeterState : ElectricMeterState.values()) {
                if(electricMeterState.state == state){
                    return  electricMeterState.name;
                }
            }
            return null;
        }
    }
}
